#include <iostream>
#include "Sock.hpp"
#include <poll.h>
#include <string>

#define NUM 128

struct pollfd fd_array[NUM]; //内容>=0,合法的fd，如果是-1,该位置没有fd

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cout << "Usage: \n\t" << argv[0] << " port" << std::endl;
        exit(1);
    }
    uint16_t port = (uint16_t)atoi(argv[1]);
    int listen_sock = Sock::Socket();
    Sock::Bind(listen_sock, port);
    Sock::Listen(listen_sock);

    for(int i=0; i<NUM; i++)
    {
        fd_array[i].fd = -1;
        fd_array[i].events = 0;
        fd_array[i].revents = 0;
    }
    fd_array[0].fd = listen_sock;
    fd_array[0].events = POLLIN;
    fd_array[0].revents = 0;
    for (;;)
    {
        // 服务器上的所有的fd(包括listen_sock),都要交给select进行检测
        // recv,read,write,send,accept : 只负责自己最核心的工作：真正的读写(listen_sock:accept)
        int n = poll(fd_array, NUM, 1000);
        switch (n)
        {
        case -1:
            std::cerr << "poll error" << std::endl;
            break;
        case 0:
            std::cout << "poll timeout" << std::endl;
            break;
        default:
            cout << "有fd对应的事件就绪啦!" << std::endl;
            for (int i = 0; i < NUM; i++)
            {
                if (fd_array[i].fd == -1) //非法fd，跳过
                    continue;
                // fd合法，开始判断是否就绪。如果没有就绪 -》 不处理
                if (fd_array[i].revents & POLLIN) //该fd的读事件就绪
                {
                    std::cout << "sock: " << fd_array[i].fd << " 上面有了读事件，可以读取了" << std::endl;
                    //分为listen套接字就绪 和 普通套接字就绪
                    if (fd_array[i].fd == listen_sock)
                    {
                        std::cout << "listen_sock: " << listen_sock << " 有了新的链接到来" << std::endl;
                        // accept
                        int sock = Sock::Accept(listen_sock);
                        if (sock >= 0)
                        {
                            std::cout << "listen_sock: " << listen_sock << " 获取新的链接成功" << std::endl;
                            // 获取成功
                            // 新链接到来，不意味着有数据到来。我们要将这个新的fd放进数组里，让他也加入select的监听
                            int pos = 1;
                            for (; pos < NUM; pos++) //去找一个空位给sock
                            {
                                if (fd_array[pos].fd == -1)
                                {
                                    break;
                                }
                            }
                            if (pos < NUM)
                            {
                                std::cout << "新链接: " << sock << " 已经被添加到了数组[" << pos << "]的位置" << std::endl;
                                fd_array[pos].fd = sock;
                                fd_array[pos].events = POLLIN;
                                fd_array[pos].revents = 0;
                            }
                            else //说明服务器满载，要关闭这个新链接
                            {
                                std::cout << "服务器已经满载了，关闭新的链接" << std::endl;
                                close(sock);
                            }
                        }
                    }
                    else //普通的套接字，直接进行读取逻辑
                    {
                        std::cout << "sock: " << fd_array[i].fd << " 上面有普通读取" << std::endl;

                        char recv_buffer[1024] = {0};
                        ssize_t s = recv(fd_array[i].fd, recv_buffer, sizeof(recv_buffer) - 1, 0);
                        if (s > 0)
                        {
                            recv_buffer[s] = 0;
                            std::cout << "client[" << fd_array[i].fd << "]# " << recv_buffer << std::endl;
                        }
                        else if (s == 0)
                        {
                            std::cout << "sock: " << fd_array[i].fd << "关闭了, client退出啦!" << std::endl;
                            //对端关闭链接,我们这边也要关掉对应的套接字
                            close(fd_array[i].fd);
                            std::cout << "已经在数组下标fd_array[" << i << "]"
                                      << "中,去掉了sock: " << fd_array[i].fd << std::endl;
                            fd_array[i].fd = -1; //该位置置为-1
                        }
                        else
                        {
                            //读取失败
                            close(fd_array[i].fd);
                            std::cout << "已经在数组下标fd_array[" << i << "]"
                                      << "中,去掉了sock: " << fd_array[i].fd << std::endl;
                            fd_array[i].fd = -1;
                        }
                    }
                }
            }
            break;
        }
    }
    return 0;
}
